/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#include "common_def.h"
#include "iot_errno.h"
#include "pwm.h"
#include "iot_pwm.h"

#define IOT_PWM_MIN_DUTY           0
#define IOT_PWM_MAX_DUTY           100
#define IOT_PWM_DUTY_PART          10
#define IOT_PWM_FREQ_PART          2
#define IOT_PWM_MAX_DIV_NUM_MAX    8
#define IOT_PWM_CFG_OFFEST_TIME    0
#define IOT_PWM_CFG_REPEAT_CYCLE   100
#define IOT_PWM_CFG_REPEAT_STATE   true

static bool g_iot_pwm_inited = false;

unsigned int IoTPwmInit(unsigned int port)
{
    if (!g_iot_pwm_inited) {
        uapi_pwm_init();
    }
    g_iot_pwm_inited = true;
#ifdef CONFIG_PWM_USING_V151
    if (uapi_pwm_set_group(port, &port, 1) != ERRCODE_SUCC) {
        return IOT_FAILURE;
    }
#endif
    return IOT_SUCCESS;
}

unsigned int IoTPwmDeinit(unsigned int port)
{
    if (g_iot_pwm_inited) {
        uapi_pwm_deinit();
    }
    g_iot_pwm_inited = false;
#ifdef CONFIG_PWM_USING_V151
    if (uapi_pwm_clear_group(port) != ERRCODE_SUCC) {
        return IOT_FAILURE;
    }
#endif
    return IOT_SUCCESS;
}

unsigned int IoTPwmStart(unsigned int port, unsigned short duty, unsigned int freq)
{
    if ((duty >= IOT_PWM_MAX_DUTY) || (duty == IOT_PWM_MIN_DUTY)) {
        return IOT_FAILURE;
    }

    uint32_t clk_freq = uapi_pwm_get_frequency((uint8_t)port);
    /* 实测值与理论值有两倍差距，怀疑是底层时钟配置问题，此处×2进行软件修正 */
    clk_freq *= 2;
    osal_printk("clk_freq: %d\r\n", clk_freq);
    uint32_t div_num = (clk_freq + freq / IOT_PWM_FREQ_PART) / freq;   // 计算分频数
    if (div_num < IOT_PWM_MAX_DIV_NUM_MAX) {
        return IOT_FAILURE;
    }
    uint32_t high_time = div_num * duty / IOT_PWM_MAX_DUTY;            // 计算高电平时钟个数（向下取整）
    if (high_time * IOT_PWM_MAX_DUTY / div_num >= (uint32_t)(duty - duty * IOT_PWM_DUTY_PART / IOT_PWM_MAX_DUTY)) {
    } else if ((high_time + 1) * IOT_PWM_MAX_DUTY / div_num <=
                (uint32_t)(duty + duty * IOT_PWM_DUTY_PART / IOT_PWM_MAX_DUTY)) {
        high_time++;
    } else {
        return IOT_FAILURE;
    }
    uint32_t low_time = div_num - high_time;
    // osal_printk("low_time: %d  high_time: %d\r\n", low_time, high_time);
    pwm_config_t cfg = {
        .low_time = low_time,
        .high_time = high_time,
        .offset_time = IOT_PWM_CFG_OFFEST_TIME,
        .cycles = IOT_PWM_CFG_REPEAT_CYCLE,
        .repeat = IOT_PWM_CFG_REPEAT_STATE
    };
    if (uapi_pwm_open((uint8_t)port, &cfg) != ERRCODE_SUCC) {
        return IOT_FAILURE;
    }
#ifdef CONFIG_PWM_USING_V151
    if (uapi_pwm_start_group((uint8_t)port) != ERRCODE_SUCC) {
        return IOT_FAILURE;
    }
#else
    if (uapi_pwm_start((uint8_t)port) != ERRCODE_SUCC) {
        return IOT_FAILURE;
    }
#endif
    return IOT_SUCCESS;
}

unsigned int IoTPwmStop(unsigned int port)
{
    if (uapi_pwm_close((uint8_t)port) != ERRCODE_SUCC) {
        return IOT_FAILURE;
    }
    return IOT_SUCCESS;
}